home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Adobe Graphics & Publishing SDK 1996 December
/
Adobe Graphics & Publishing SDK 1996 December.iso
/
mac
/
After Effects 3.1 SDK Mac
/
Examples
/
Effects Samples
/
Shifter
/
Shifter.c
< prev
Wrap
Text File
|
1996-11-06
|
10KB
|
358 lines
/**
Shifter.c
Part of the Adobe After Effects 3.1 SDK.
Copyright (c)1993-96, Adobe Systems Inc, All Rights Reserved.
This effect shifts the whole image to a new position with
sub-pixel accuracy. The user specifies a point, and the
center of the layer is shifted to that point. The user
also specifies a "Blend With Original" so the shifted image
can appear as a faded echo of the original.
This demonstrates the use of:
the Iterate callback
the Subpixel Sample callback
a Point control
a Fixed Slider control
the Extent Hint rectangle (from the output image)
Revision History
1.0, created by rb, 12 March 93
1.1, updated for AE 2.0, dmw, 11 Jan 94
1.2, updated for AE 2.0 PowerMac/Mac, dmw
2.0, updated for AE 3.0, CW7, dmw
2.1, Added call to AEFX_CLR_STRUCT macro to clear out PF_ParamDef, ba, 6 Nov 96
**/
#include "AE_EffectCB.h"
#include "AE_Macros.h"
#include <A4Stuff.h>
#define MAJOR_VERSION 2
#define MINOR_VERSION 0
#define BUG_VERSION 0
#define STAGE_VERSION PF_Stage_RELEASE
#define BUILD_VERSION 0
#define NAME "Shifter"
/** Parameter Definition Constants
Here we define the parameters, their default
settings, and minimum and maximum values.
**/
enum {
SHIFT_INPUT = 0, /* params index of default input layer */
SHIFT_DISPLACE, /* params index of offset point control */
SHIFT_BLEND, /* " " of blend with original slider */
SHIFT_NUM_PARAMS
};
/* set default (x,y) of new center to the
* original center of the image (50%, 50%).
*/
#define SHIFT_DISPLACE_X_DFLT (50L << 16)
#define SHIFT_DISPLACE_Y_DFLT (50L << 16)
/* set blend to default to showing just the shifted version
* of the image. Zero will represented full shifted, one will
* be full original, and in-between values will be blended.
* All of these numbers are in Fixed point.
*/
#define SHIFT_BLEND_MIN (0L << 16)
#define SHIFT_BLEND_MAX (1L << 16)
#define SHIFT_BLEND_DFLT (0L << 16)
/** Command Specific Subroutines
This plug-in only deals with the commands:
PF_Cmd_ABOUT
PF_Cmd_GLOBAL_SETUP
PF_Cmd_GLOBAL_SETDOWN
PF_Cmd_PARAMS_SETUP
PF_Cmd_RENDER
All other commands are ignored. There is a routine for
each command, and a main routine to dispatch at the bottom.
**/
static PF_Err About (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
#define DESCRIPTION "Blend in a shifted copy of the image."
PF_SPRINTF(out_data->return_msg, "%s, v%d.%d\r%s",
NAME, MAJOR_VERSION, MINOR_VERSION, DESCRIPTION);
return PF_Err_NONE;
}
static PF_Err GlobalSetup (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
PF_Err err = PF_Err_NONE;
/* Need to let AE know what version of the "Shifter" plug-in
* we are......
*/
out_data->my_version = PF_VERSION(MAJOR_VERSION, MINOR_VERSION,
BUG_VERSION, STAGE_VERSION, BUILD_VERSION);
/* We are only going to iterate over the output extent
* Rectange, so we need to specify that flag...
*/
out_data->out_flags |= PF_OutFlag_USE_OUTPUT_EXTENT;
return err;
}
static PF_Err GlobalSetdown (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
/* We haven't actually allocated any global data,
* so we don't need to do anything here... */
return PF_Err_NONE;
}
static PF_Err ParamsSetup (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output)
{
PF_Err err = PF_Err_NONE;
PF_ParamDef def; /* scratch space for a parameter definition */
/* Always clear out the PF_ParamDef structure before adding your parameters,
* this macro will do that. */
AEFX_CLR_STRUCT(def);
/* Create the POINT parameter... */
def.param_type = PF_Param_POINT;
PF_STRCPY(def.name, "Shift Center To");
def.flags = 0;
def.u.td.x_value = def.u.td.x_dephault = SHIFT_DISPLACE_X_DFLT;
def.u.td.y_value = def.u.td.y_dephault = SHIFT_DISPLACE_Y_DFLT;
def.u.td.restrict_bounds = FALSE; /* point can be anywhere */
if (err = PF_ADD_PARAM(in_data, -1, &def)) return err;
/* Create the FIXED SLIDER parameter...
* Note: now that we have called ADD_PARAM, we can re-use
* the same PF_ParamDef for the slider definition. */
def.param_type = PF_Param_FIX_SLIDER;
PF_STRCPY(def.name, "Blend With Original");
def.flags = 0;
/* NOTE: we must set these strings to empty strings to prevent
* garbage text from being displayed above our sliders... */
def.u.fd.value_str[0] = def.u.fd.value_desc[0] = '\0';
def.u.fd.value = def.u.fd.dephault = SHIFT_BLEND_DFLT;
/* NOTE: for this Blend slider, the valid min and max are
* the same as the min and max accessible by the slider. */
def.u.fd.valid_min = def.u.fd.slider_min = SHIFT_BLEND_MIN;
def.u.fd.valid_max = def.u.fd.slider_max = SHIFT_BLEND_MAX;
/* Let's let the user see 1 decimal place of precision,
* and have the value appear to go from 0 to 100 percent,
* rather than from 0 to 1 as it's stored internally... */
def.u.fd.precision = 1;
def.u.fd.display_flags = 1; /* display as percent flag */
if (err = PF_ADD_PARAM(in_data, -1, &def)) return err;
/* Set number of parameters before leaving */
out_data->num_params = SHIFT_NUM_PARAMS;
return err;
}
/* Iteration Function
* The render routine uses PF_ITERATE to loop over all the pixels.
* This function adds an offset to the given pixel and resamples
* the original image at that offset point. We will blend this
* shifted image back with the original in the Render routine.
*
* We will define a type called a ShiftInfo that contains all of
* the information our ShiftImage function needs to know about
* the effect parameters, and the stuff to do image resampling.
*/
typedef struct {
Fixed x_off; /* x_offset for shifted image */
Fixed y_off; /* y_offset for shifted image */
/* structures and function pointer for image resampling */
PF_ProgPtr ref;
PF_SampPB samp_pb;
PF_InData *in_data;
} ShiftInfo;
static PF_Err ShiftImage (long refcon, long x, long y, PF_Pixel *in, PF_Pixel *out)
{
register ShiftInfo *si = (ShiftInfo *)refcon;
PF_InData *in_data = si->in_data;
PF_Err err;
Fixed new_x, new_y;
/* Resample original image at the offset point */
new_x = ((long)x << 16) + si->x_off; /* convert value to Fixed */
new_y = ((long)y << 16) + si->y_off;
err = PF_SUBPIXEL_SAMPLE(new_x, new_y, &si->samp_pb, out);
return err;
}
/* Render
* To render our image, we need to set up a ShiftInfo structure
* with the right information, then invoke the Iterate callback.
* We will iterate only over the visible range of the output
* image (that is, its extent hint), to save time. Once we have
* created the shifted image in the output buffer, we will blend
* the input image into the output image.
*
* NOTE: Using the Blend callback gives us an alpha-weighted
* blend of the two images, so we will not get inappropriate
* color distortions where the images do not overlap, or where
* there is partial alpha. Alpha weighting the color mixture
* is a subtle thing that users may not consciously notice,
* but gives better looking results, which they will.
*
* NOTE: You will find that blending looks distinctly different
* from compositing the shifted image onto the original -- where
* the shifted copy does not overlap the original, it becomes
* partially (or totally) transparent. Compositing would not
* do that. Compositing could make an interesting effect, too,
* but there is no need for it. It can be easily achieved by
* duplicating the layer, shifting the duplicate, and setting
* the transparency slider.
*/
static PF_Err Render (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
PF_Err err = PF_Err_NONE;
ShiftInfo si;
Fixed blend;
short lines;
PF_World *input;
input = ¶ms[SHIFT_INPUT]->u.ld;
blend = params[SHIFT_BLEND]->u.fd.value;
/* We convert the image width and height to Fixed values
* then divide by two, to calculate the Fixed point offset.
* Shifting left 15 bits effectively does this conversion.
*/
si.x_off = ((long)input->width << 15) - /* 1/2 width as Fixed */
params[SHIFT_DISPLACE]->u.td.x_value;
si.y_off = ((long)input->height << 15) - /* 1/2 height as Fixed */
params[SHIFT_DISPLACE]->u.td.y_value;
si.ref = in_data->effect_ref;
si.samp_pb.src = input;
si.in_data = in_data;
if (blend == (1L << 16)) {
/* if blend is set to 100%, we don't have any work to do */
err = PF_COPY(input, output, NULL, NULL);
} else {
/* otherwise, iterate and blend */
/* calculate how many lines we'll iterate over, for progress bar */
lines = output->extent_hint.bottom - output->extent_hint.top;
err = PF_ITERATE(0, lines, input, &output->extent_hint,
(long)&si, ShiftImage, output);
/* one of the advantages of using ITERATE, is that it
* automatically checks for user interruptions for us.
* It will return an error if the user interrupted, which
* we should dutifully pass back to the application.
*/
if (!err) {
err = PF_BLEND(output, input, blend, output);
}
}
return err;
}
PF_Err main (
PF_Cmd cmd,
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
PF_Err err = PF_Err_NONE;
EnterCodeResource(); /* $$$ this assumes you're using Metrowerks */
switch (cmd) {
case PF_Cmd_ABOUT:
err = About(in_data,out_data,params,output);
break;
case PF_Cmd_GLOBAL_SETUP:
err = GlobalSetup(in_data,out_data,params,output);
break;
case PF_Cmd_PARAMS_SETUP:
err = ParamsSetup(in_data,out_data,params,output);
break;
case PF_Cmd_GLOBAL_SETDOWN:
err = GlobalSetdown(in_data,out_data,params,output);
break;
case PF_Cmd_RENDER:
err = Render(in_data,out_data,params,output);
break;
}
ExitCodeResource();
return err;
}